<?php

namespace fastphp;

use Exception;

/**
 * 中间件管理器
 * 负责注册、组织和执行中间件
 */
class MiddlewareManager
{
    /**
     * 全局中间件数组
     * @var array
     */
    protected $globalMiddlewares = [];
    
    /**
     * 路由组中间件数组
     * @var array
     */
    protected $groupMiddlewares = [];
    
    /**
     * 路由特定中间件数组
     * @var array
     */
    protected $routeMiddlewares = [];
    
    /**
     * 中间件别名映射
     * @var array
     */
    protected $middlewareAliases = [];
    
    /**
     * 核心容器
     * @var Core
     */
    protected $container;
    
    /**
     * 构造函数
     * 
     * @param Core $container 核心容器
     */
    public function __construct(Core $container)
    {
        $this->container = $container;
    }
    
    /**
     * 注册全局中间件
     * 
     * @param string|array $middleware 中间件类名或别名
     * @return $this
     */
    public function addGlobal($middleware)
    {
        if (is_array($middleware)) {
            foreach ($middleware as $item) {
                $this->globalMiddlewares[] = $item;
            }
        } else {
            $this->globalMiddlewares[] = $middleware;
        }
        return $this;
    }
    
    /**
     * 注册路由中间件
     * 
     * @param string $name 中间件名称
     * @param string $class 中间件类名
     * @return $this
     */
    public function alias($name, $class)
    {
        $this->middlewareAliases[$name] = $class;
        return $this;
    }
    
    /**
     * 为路由组添加中间件
     * 
     * @param string|array $middleware 中间件类名或别名
     * @return $this
     */
    public function addGroup($middleware)
    {
        if (is_array($middleware)) {
            foreach ($middleware as $item) {
                $this->groupMiddlewares[] = $item;
            }
        } else {
            $this->groupMiddlewares[] = $middleware;
        }
        return $this;
    }
    
    /**
     * 为特定路由添加中间件
     * 
     * @param string $routeName 路由名称
     * @param string|array $middleware 中间件类名或别名
     * @return $this
     */
    public function addRoute($routeName, $middleware)
    {
        if (!isset($this->routeMiddlewares[$routeName])) {
            $this->routeMiddlewares[$routeName] = [];
        }
        
        if (is_array($middleware)) {
            foreach ($middleware as $item) {
                $this->routeMiddlewares[$routeName][] = $item;
            }
        } else {
            $this->routeMiddlewares[$routeName][] = $middleware;
        }
        return $this;
    }
    
    /**
     * 执行中间件链
     * 
     * @param Request $request 请求对象
     * @param Response $response 响应对象
     * @param callable $action 最终要执行的控制器动作
     * @param string $routeName 路由名称（可选）
     * @return mixed
     */
    public function execute($request, $response, callable $action, $routeName = null)
    {
        // 收集所有需要执行的中间件
        $middlewares = $this->globalMiddlewares;
        
        // 添加路由组中间件
        $middlewares = array_merge($middlewares, $this->groupMiddlewares);
        
        // 添加路由特定中间件
        if ($routeName && isset($this->routeMiddlewares[$routeName])) {
            $middlewares = array_merge($middlewares, $this->routeMiddlewares[$routeName]);
        }
        
        // 构建中间件链
        $stack = $action;
        
        // 从后往前构建中间件链
        foreach (array_reverse($middlewares) as $middleware) {
            $stack = $this->createMiddlewareClosure($middleware, $stack);
        }
        
        // 执行中间件链
        return $stack($request, $response);
    }
    
    /**
     * 创建中间件闭包函数
     * 
     * @param string $middleware 中间件类名或别名
     * @param callable $next 下一个中间件或最终处理函数
     * @return callable
     */
    protected function createMiddlewareClosure($middleware, callable $next)
    {
        // 获取实际的中间件类名
        $className = $this->getMiddlewareClass($middleware);
        
        // 返回闭包函数
        return function ($request, $response) use ($className, $next) {
            // 实例化中间件
            $instance = $this->resolveMiddleware($className);
            
            // 调用中间件的handle方法
            return $instance->handle($request, $response, $next);
        };
    }
    
    /**
     * 获取中间件类名
     * 
     * @param string $middleware 中间件类名或别名
     * @return string
     */
    protected function getMiddlewareClass($middleware)
    {
        // 如果是别名，返回实际的类名
        if (isset($this->middlewareAliases[$middleware])) {
            return $this->middlewareAliases[$middleware];
        }
        
        // 检查是否是完整的命名空间类名
        if (strpos($middleware, '\\') !== false) {
            return $middleware;
        }
        
        // 尝试添加默认命名空间
        return 'application\middleware\\' . $middleware;
    }
    
    /**
     * 解析中间件实例
     * 
     * @param string $className 中间件类名
     * @return Middleware
     * @throws Exception
     */
    protected function resolveMiddleware($className)
    {
        // 检查中间件类是否存在
        if (!class_exists($className)) {
            throw new Exception("中间件类不存在: {$className}");
        }
        
        // 实例化中间件
        $instance = new $className();
        
        // 检查是否实现了Middleware接口
        if (!($instance instanceof Middleware)) {
            throw new Exception("中间件类未实现Middleware接口: {$className}");
        }
        
        return $instance;
    }
}